#include "client.h"

//为防止一次不能发送完想发送的数据，此处采用Sendn。
int Sendn(int fd, void* buf, int len) {
    char* bufChar = (char*)buf;
    int size = len;
    while(size > 0) {
        int ret = send(fd, bufChar, size, 0);
        if(ret < 0) {
            perror("sendn");
            return len - size;
        }
        size -= ret;
        bufChar += ret;
    }
    return len - size;
}


//客户端上传文件
int SendFile(char* srcName, char* destName, int peerFd) {
    //定义train类型的对象
    Train_t train;
    //打开文件
    int fd = open(srcName, O_RDWR);
    if(fd == -1) {
        perror("open");
        return -1;
    }
    //发送文件名
    memset(&train, 0, sizeof(train));
    train.lenth = strlen(destName);
    memcpy(train.buf, destName, train.lenth);
    Sendn(peerFd, &train, 4 + train.lenth);
    //printf("%s\n", train.buf);
    //发送md5码
    char md5[1024] = {0};
    int ret = get_file_md5(srcName, md5);
    memset(&train, 0, sizeof(train));
    train.lenth = strlen(md5);
    memcpy(train.buf, md5, train.lenth);
    Sendn(peerFd, &train, 4 + train.lenth);
    //printf("%s\n", md5);
    //发送文件大小
    off_t FileSize;
    memset(&train, 0, sizeof(Train_t));
    struct stat statbuf;
    ret = fstat(fd, &statbuf);
    if(ret == -1) {
        perror("fstat");
        return -1;
    }
    FileSize = statbuf.st_size;
    train.lenth = sizeof(off_t);
    memcpy(train.buf, &FileSize, train.lenth);
    Sendn(peerFd, train.buf, train.lenth);
    //接收对方所告知的已传文件大小，若接收到-1，表明路径有问题，-2表明已有相同的物理文件
    off_t byteHaveSend = 0;
    ret = recv(peerFd, &byteHaveSend, sizeof(off_t), MSG_WAITALL);
    if(ret == -1) {
        perror("recv");
        return -1;
    }
    if(byteHaveSend == -1) {
        printf("wrong pathname\n");
        return 0;
    } else if(byteHaveSend == -2) {
        printf("quick upload success\n");
        return 0;
    }
    //采用零拷贝发送文件内容
    void* buf = mmap(NULL, FileSize - byteHaveSend, PROT_WRITE | PROT_READ, MAP_SHARED, fd, byteHaveSend);
    if(buf == MAP_FAILED) {
        perror("mmap");
        return -1;
    }
    Sendn(peerFd, buf, FileSize - byteHaveSend);
    munmap(buf, FileSize);
    //关闭文件并返回
    close(fd);
    return 0;
}


